package com.sdk.es.http.config;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import jakarta.annotation.Resource;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;

import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Configuration
public class ElasticsearchConfigurationImpl extends ElasticsearchConfiguration {
    @Resource
    private ElasticsearchProperties properties;

    @Override
    public ClientConfiguration clientConfiguration() {
        List<String> uris = Assert.notEmpty(properties.getUris());
        String username = Assert.notBlank(properties.getUsername());
        String password = Assert.notBlank(properties.getPassword());
        return ClientConfiguration.builder()
                .connectedTo(uris.toArray(new String[0]))
                .withConnectTimeout(Optional.ofNullable(properties.getConnectionTimeout()).orElse(Duration.ofSeconds(5)))
                .withSocketTimeout(Optional.ofNullable(properties.getSocketTimeout()).orElse(Duration.ofSeconds(3)))
                .withBasicAuth(username, password)
                .build();
    }

    private static final DateTimeFormatter CH = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");

    @Bean
    @Override
    public ElasticsearchCustomConversions elasticsearchCustomConversions() {
        List<Converter<?, ?>> converters = new ArrayList<>();
        converters.add(LocalDateTimeToStringConverter.INSTANCE);
        converters.add(LongToLocalDateTimeConverter.INSTANCE);
        converters.add(StringToLocalDateTimeConverter.INSTANCE);
        return new ElasticsearchCustomConversions(converters);
    }

    @ReadingConverter
    enum StringToLocalDateTimeConverter implements Converter<String, LocalDateTime> {

        INSTANCE;

        @Override
        public LocalDateTime convert(String source) {
            if (StrUtil.isBlank(source)) {
                return null;
            }
            if(source.length() > 23){
                return LocalDateTime.parse(source, CH);
            }else {
                return LocalDateTimeUtil.parse(source);
            }
        }
    }

    @ReadingConverter
    enum LongToLocalDateTimeConverter implements Converter<Long, LocalDateTime> {

        INSTANCE;

        @Override
        public LocalDateTime convert(Long timestamp) {
            if (Objects.isNull(timestamp)) {
                return null;
            }
            return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());
        }
    }


    @WritingConverter
    enum LocalDateTimeToStringConverter implements Converter<LocalDateTime, String> {

        INSTANCE;

        @Override
        public String convert(LocalDateTime localDateTime) {
            return localDateTime.atZone(ZoneId.of("Asia/Shanghai")).format(CH);
        }
    }

    public static void main(String[] args) {
        System.out.println("2034-12-12T00:23:46.000".length());
    }
}
